﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace Prsrp
{
    /// <summary>
    /// BasePhysic represent any object taked in account by the physic engine.
    /// </summary>
    public class BasePhysic : BaseDisplayable
    {
        #region Collision Properties

        // Collision Flags (unused for now)
        protected bool mbCollisionLeft = true;
        protected bool mbCollisionRight = true;
        protected bool mbCollisionTop = true;
        protected bool mbCollisionBottom = true;
        protected bool mbCenterColX = true;
        protected bool mbCenterColY = false;

        #endregion

        #region Physic Properties

        // Speed Vector
        public Vector2 mvSpeed;

        // Weight (todo: use this with gravity!)
        protected float mfWeight = 1;

        protected bool mbAffectedByAirFriction = true;
        protected bool mbAffectedByGravity = false;

        protected float mfAirFrictionMultiplier = 1f;
        protected float mfGravityMultiplier = 1f;

        #endregion

        /// <returns>
        /// Return the result of @mvSpeed after physics calculations.
        /// </returns>
        /// <remarks>
        /// Warning: This function DOES NOT affect actual @mvSpeed.
        /// </remarks>
        private Vector2 GetNextFrameSpeed()
        {
            Vector2 vNextFrameSpeed = mvSpeed;

            //  Handle Air Friction
            if (mbAffectedByAirFriction)
            {
                vNextFrameSpeed *= GameGlobals.AirFriction * mfAirFrictionMultiplier;
            }
            // Handle Gravity
            if (mbAffectedByGravity)
            {
                vNextFrameSpeed.Y += GameGlobals.Gravity * mfWeight * mfGravityMultiplier;
            }

            return vNextFrameSpeed;
        }

        /// <remarks>
        /// Warning: This function DOES NOT affect actual @mvPos.
        /// </remarks>
        /// <returns>Return the result of @mvPos after physics calculations.</returns>
        private Vector2 GetNextFramePos()
        {
            Vector2 vNextFrameSpeed = GetNextFrameSpeed();

            return mvPos + vNextFrameSpeed;
        }

        public void HandlePhysics()
        {
            mvSpeed = GetNextFrameSpeed();
            mvPos = mvPos + mvSpeed;
        }

        public void HandleCollision (BasePhysic _pTarget)
        {
            // Get Predictions
            Vector2   vNewSourcePos    = GetNextFramePos();
            Vector2   vNewTargetPos    = _pTarget.GetNextFramePos();
            Rectangle rCurSourceHitBox  = GetHitBox();
            Rectangle rCurTargetHitBox  = _pTarget.GetHitBox();
            Rectangle rNewSourceHitBox = GetHitBox(vNewSourcePos);
            Rectangle rNewTargetHitBox = _pTarget.GetHitBox(vNewTargetPos);

            // Get Various Data (I know it's a lot...)
            int iCurSourceColL = mbCenterColX ? (int)rCurSourceHitBox.Center.X : rCurSourceHitBox.Left;
            int iCurSourceColR = mbCenterColX ? (int)rCurSourceHitBox.Center.X : rCurSourceHitBox.Right;
            int iCurSourceColT = mbCenterColY ? (int)rCurSourceHitBox.Center.Y : rCurSourceHitBox.Top;
            int iCurSourceColB = mbCenterColY ? (int)rCurSourceHitBox.Center.Y : rCurSourceHitBox.Bottom;
            int iCurTargetColL = mbCenterColX ? (int)rCurTargetHitBox.Center.X : rCurTargetHitBox.Left;
            int iCurTargetColR = mbCenterColX ? (int)rCurTargetHitBox.Center.X : rCurTargetHitBox.Right;

            int iNewSourceColL = mbCenterColX ? (int)rNewSourceHitBox.Center.X : rNewSourceHitBox.Left;
            int iNewSourceColR = mbCenterColX ? (int)rNewSourceHitBox.Center.X : rNewSourceHitBox.Right;
            int iNewSourceColT = mbCenterColY ? (int)rNewSourceHitBox.Center.Y : rNewSourceHitBox.Top;
            int iNewSourceColB = mbCenterColY ? (int)rNewSourceHitBox.Center.Y : rNewSourceHitBox.Bottom;
            
            int iNewTargetColL = mbCenterColX ? (int)rNewTargetHitBox.Center.X : rNewTargetHitBox.Left;;
            int iNewTargetColR = mbCenterColX ? (int)rNewTargetHitBox.Center.X : rNewTargetHitBox.Right;
            int iCurTargetColT = mbCenterColY ? (int)rCurTargetHitBox.Center.Y : rCurTargetHitBox.Top;
            int iNewTargetColT = mbCenterColY ? (int)rNewTargetHitBox.Center.Y : rNewTargetHitBox.Top;
            int iCurTargetColB = mbCenterColY ? (int)rCurTargetHitBox.Center.Y : rCurTargetHitBox.Bottom;
            int iNewTargetColB = mbCenterColY ? (int)rNewTargetHitBox.Center.Y : rNewTargetHitBox.Bottom;

            bool bIntersectXL = iNewSourceColL >= iNewTargetColL && iNewSourceColL <= iNewTargetColR;
            bool bIntersectXR = iNewSourceColR >= iNewTargetColL && iNewSourceColR <= iNewTargetColR;
            bool bIntersectX  = bIntersectXL || bIntersectXR;

            bool bIntersectYT = (iNewSourceColT >= iNewTargetColT && iNewSourceColT < iNewTargetColB);
            bool bIntersectYB = (iNewSourceColB > iNewTargetColT && iNewSourceColB <= iNewTargetColB);
            bool bIntersectY  = bIntersectYT || bIntersectYB;

            if (bIntersectX)
            {
                // Check if @_pTarget collide with source top side.
                if (iCurTargetColB < iCurSourceColT && iNewTargetColB >= iNewSourceColT) 
                {
                    mvSpeed.Y = 0; _pTarget.mvSpeed.Y = 0;
                }

                // Check if @_pTarget collide with source bottom side.
                if (iCurTargetColT > iCurSourceColB && iNewTargetColT <= iNewSourceColB)
                {
                    mvSpeed.Y = 0; _pTarget.mvSpeed.Y = 0;
                }
            }
            

            if (bIntersectY)
            {
                // Check if @_pTarget collide with source left side.
                if (iCurTargetColR < iCurSourceColL && iNewTargetColR >= iNewSourceColL)
                {
                    mvSpeed.X = 0; _pTarget.mvSpeed.X = 0;
                }

                // Check if @_pTarget collide with source right side.
                if (iCurTargetColL > iCurSourceColR && iNewTargetColL <= iNewSourceColR)
                {
                    mvSpeed.X = 0; _pTarget.mvSpeed.X = 0;
                }
            }
        }
    }
}
